package org.geoscrape.util;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;

import org.geoscrape.Location;

/**
 * Estimates the type and location of a cache based on the grid location,
 * relative grid location, zoom level, and tile image.
 * 
 */
public class CacheEstimator
{
	private String name;
	private List<Point> points = new ArrayList<Point>();
	private Point upperLeftCorner;
	private Point lowerRightCorner;
	private String magicString;
	private boolean overlapping;
	private Point pixellocation;
	private Point gridSquare;
	private int zoomlevel;

	public CacheEstimator(String name)
	{
		this.name = name;
	}

	public Location estimateLocation()
	{
		double scale = 256*Math.pow(2,zoomlevel);
		long x = gridSquare.x * 256;
		long y = gridSquare.y * 256;
		if (pixellocation != null)
		{
			x += pixellocation.x;
			y += pixellocation.y;
		}
		else
		{
			Point c = getCenter();
			x += c.x * 4;
			y += c.y * 4;
		}
		double dx =(x*360)/scale;
		double lon = dx-180;
		
		double dy = Math.PI-(y*2.0*Math.PI)/scale;
		double lat = Math.atan(Math.sinh(dy));
		lat = Math.toDegrees(lat);

		return new Location(lat, lon);
	}

	public String getName()
	{
		return name;
	}

	/**
	 * Two cache estimators are the same if they have the same name.
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj)
	{
		if (obj instanceof CacheEstimator)
		{
			if (this.getName().equals(((CacheEstimator) obj).getName()))
			{
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
	}

	public void addPoint(Point nuPoint)
	{
		this.points.add(nuPoint);
	}

	public Point getCenter()
	{
		getUpperLeftCorner();
		getLowerRightCorner();
		Point res = new Point();
		res.setLocation((lowerRightCorner.x - upperLeftCorner.x) / 2.0 + upperLeftCorner.x,
				(lowerRightCorner.y - upperLeftCorner.y) / 2.0 + upperLeftCorner.y);
		return res;
	}

	public Rectangle getTileImageRect()
	{
		getUpperLeftCorner();
		getLowerRightCorner();
		Rectangle res = new Rectangle(upperLeftCorner);
		res.x *= 4;
		res.y *= 4;
		res.width = getWidth() * 4;
		res.height = getHeight() * 4;
		return res;
	}

	private int getWidth()
	{
		return lowerRightCorner.x - upperLeftCorner.x + 1;
	}

	private int getHeight()
	{

		return lowerRightCorner.y - upperLeftCorner.y + 1;
	}

	public Point getUpperLeftCorner()
	{

		if (points.size() > 0)
		{
			Point p = points.get(0);
			upperLeftCorner = new Point(p.x, p.y);
			for (int t = 1; t < points.size(); t++)
			{
				if (upperLeftCorner.x > points.get(t).x)
				{
					upperLeftCorner.x = points.get(t).x;
				}
				if (upperLeftCorner.y > points.get(t).y)
				{
					upperLeftCorner.y = points.get(t).y;
				}
			}
		}
		return upperLeftCorner;
	}

	public Point getLowerRightCorner()
	{
		if (points.size() > 0)
		{
			Point p = points.get(0);
			lowerRightCorner = new Point(p.x, p.y);
			for (int t = 1; t < points.size(); t++)
			{
				if (lowerRightCorner.x < points.get(t).x)
				{
					lowerRightCorner.x = points.get(t).x;
				}
				if (lowerRightCorner.y < points.get(t).y)
				{
					lowerRightCorner.y = points.get(t).y;
				}
			}
		}
		return lowerRightCorner;
	}

	public void setMagicString(String string)
	{
		this.magicString = string;
	}

	/**
	 * The magic string is used in detail queries to the website.
	 * 
	 * @return the magicString
	 */
	public String getMagicString()
	{
		return magicString;
	}

	public void setOverlapping(boolean isOverlapping)
	{
		this.overlapping = isOverlapping;
	}

	public boolean isOverlapping()
	{
		return overlapping;
	}

	public void setPixelLocation(Point location)
	{
		this.pixellocation = location;
	}

	public void setGridSquare(Point gridSquare)
	{
		this.gridSquare = gridSquare;
	}

	public void setZoomlevel(int zoomlevel)
	{
		this.zoomlevel = zoomlevel;
	}

}
